package covertjava.protect;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.Serializable;
import java.io.*;

/**
 * <p>Encrypts and dycripts serializable objects based on a password using JCA</p>
 * <p>Copyright: Copyright (c) 2004 Sams Publishing</p>
 * @author Alex Kalinovsky
 * @version 1.0
 */
public class Encryptor {

    Cipher encCipher = null;
    Cipher decCipher = null;
    SecretKey secretKey = null;
    private static byte[] keyParams = {
        (byte)0x10, (byte)0x15, (byte)0x01, (byte)0x04,
        (byte)0x55, (byte)0x06, (byte)0x72, (byte)0x01
    };
    private static int iter_count = 20;

    /**
     * Constructs the Encryptor using hardcoded algorithm
     * @param password char[] password that is used to parameterize the encryption algorithm
     */
    public Encryptor(char[] password) throws Exception {
        PBEKeySpec keySpec = new PBEKeySpec(password);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        secretKey = keyFactory.generateSecret(keySpec);

        PBEParameterSpec paramSpec = new PBEParameterSpec(keyParams, iter_count);
        this.encCipher = Cipher.getInstance("PBEWithMD5AndDES");
        this.encCipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
        this.decCipher = Cipher.getInstance("PBEWithMD5AndDES");
        this.decCipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
    }

    public Serializable encryptObject(Serializable object) throws Exception {
        return new SealedObject(object, this.encCipher);
    }

    public Object decryptObject(Serializable object) throws Exception {
        return ((SealedObject)object).getObject(this.decCipher);
    }

    /**
     * Demonstrates using the Encryptor class
     */
    public static void main(String[] args) throws Exception {
        char[] password = {'c', 'h', 'a', 't'};

        if (args.length != 1) {
            System.out.println("Syntax: Encryptor <enc> | <dec>");
            System.exit(1);
        }

        Encryptor encryptor = new Encryptor(password);
        if ("enc".equals(args[0])) {
            String msg = "This is a test message";
            Serializable encryptedMessage = encryptor.encryptObject(msg);
            ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("message.enc"));
            stream.writeObject(encryptedMessage);
            stream.close();
            System.out.println("Wrote message: " + msg);
        }
        else {
            ObjectInputStream stream = new ObjectInputStream(new FileInputStream("message.enc"));
            Serializable encryptedMessage = (Serializable)stream.readObject();
            stream.close();
            String msg = (String)encryptor.decryptObject(encryptedMessage);
            System.out.println("Read message : " + msg);
        }

    }

}
